<?php


namespace RedMVC\Model;
use RedMVC;

/**
 * AModel class
 *  
 * @category    RedMVC
 * @package     Model
 * @author      Jan Fischer, bitWorking <info@bitworking.de>
 */
abstract class AModel{

    protected $db;
    protected $table;
    protected $primary;
    protected $fields = array();
    protected $values = array();
    
    public function __construct(array $values = null){
        if(null !== $values){            
            foreach($values as $key=>$value){                
                $this->$key = $value;
            }
        }
        $this->setDb();
        $this->init($values);
    }
    
    public function init(array $values = null){
    
    }

    public function setDb(){
        $this->db = RedMVC\Registry::get('RedMVC_Db');
    }
    
    public function __set($key, $value){
        if(in_array($key, $this->fields)){
            $this->values[$key] = $value;            
        }
    }
    
    public function __get($key){
        if(array_key_exists($key, $this->values)){
            return $this->values[$key];
        }
        return null;
    }
    
    public function __unset($key){
        if(array_key_exists($key, $this->values)){
            unset($this->values[$key]);
        }
    }
    
    public function __isset($key){
        if(array_key_exists($key, $this->values)){
            return true;
        }
        return false;
    }
    
    public function toArray(){
        $array = array();
        foreach($this->values as $key => $value){
            if(is_bool($value)){
                $array[$key] = (int) $value;
            }
            else{
                $array[$key] = $value;
            }
        }
        return $array;
    }
    
    public function save(){
        $data = $this->toArray();
        if(array_key_exists($this->primary, $data) && $data[$this->primary] != '' && $data[$this->primary] != null){
            $where = array($this->primary=>$data[$this->primary]);
            unset($data[$this->primary]);
            $this->db->update($this->table, $data, $where);
        }
        else{
            if(isset($data[$this->primary])){
                unset($data[$this->primary]);
            }
            $insertId = $this->db->insert($this->table, $data);
            $this->values[$this->primary] = $insertId;
        }
        return $this;
    }
    
    public static function delete($id){
        $class = new static();
        return $class->_delete($id);
    }
    
    protected function _delete($id){
        $sql = "DELETE FROM ".$this->table;
        $sql .= $this->_whereCondition($id);
        $this->_query($sql, $id);
        if($this->db->affectedRows() > 0){
            return true;
        }
        return false;
    }
    
    public static function fetchAll($selectSuffix = '', array $args = array()){        
        $class = new static();
        return $class->_fetchAll($selectSuffix, $args);
    }
    
    protected function _fetchAll($selectSuffix, array $args = array()){
        $sql        = "SELECT * FROM ".$this->table.' '.$selectSuffix;
        $results    = $this->db->fetch($sql, $args);
        $out        = array();
        foreach($results as $result){
            $out[] = new static($result);
        }
        return $out;
    }
    
    public static function byId($id){
        $class = new static();
        return $class->_byId($id);
    }
    
    protected function _byId($id){
        $sql        = "SELECT * FROM ".$this->table;
        $sql        .= $this->_whereCondition($id);
        $results    = $this->_fetch($sql, $id);
        if(count($results) > 0){            
            return new static($results[0]);
        }
        return null;
    }
    
    public static function byKey($key, $value, $selectSuffix = '', $operator = '='){
        $class = new static();
        return $class->_byKey($key, $value, $selectSuffix, $operator);
    }
    
    protected function _byKey($key, $value, $selectSuffix, $operator){
        $sql        = "SELECT * FROM ".$this->table." WHERE ".$key." $operator '%s' ".$selectSuffix;
        $results    = $this->db->fetch($sql, array($value));
        if(count($results) > 0){            
            $out = array();
            foreach($results as $result){
                $out[] = new static($result);
            }
            return $out;
        }
        return null;
    }
    
    public static function byKeys(array $keyValues, $selectSuffix = ''){
        $class = new static();
        return $class->_byKeys($keyValues, $selectSuffix);
    }
    
    protected function _byKeys(array $keyValues, $selectSuffix){
        $sql        = "SELECT * FROM ".$this->table;
        $sql        .= $this->_whereCondition($keyValues);
        $sql        .= ' '.$selectSuffix;
        $results    = $this->_fetch($sql, $keyValues);
        if(count($results) > 0){
            $out = array();
            foreach($results as $result){
                $out[] = new static($result);
            }
            return $out;
        }
        return null;
    }
    
    protected function _whereCondition($values){
        if(is_array($values)){
            $wheres = array();
            $keys   = array_keys($values);
            foreach($keys as $key){
                $wheres[] = "$key='%s'";
            }
            return " WHERE ".implode(' AND ', $wheres);
        }
        return " WHERE ".$this->primary."='%s'";
    }
    
    protected function _query($sql, $values){
        if(is_array($values)){
            $this->db->query($sql, array_values($values));
            return;
        }
        $this->db->query($sql, array($values));
    }
    
    protected function _fetch($sql, $values){
        if(is_array($values)){
            return $this->db->fetch($sql, array_values($values));
        }
        return $this->db->fetch($sql, array($values));
    }
}